home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / picasso96.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  73KB  |  2,252 lines

  1. /*
  2.  * UAE - The U*nix Amiga Emulator
  3.  *
  4.  * Picasso96 Support Module
  5.  *
  6.  * Copyright 1997 Brian King <Brian_King@Mitel.com, Brian_King@Cloanto.com>
  7.  *
  8.  * Theory of operation:
  9.  * On the Amiga side, a Picasso card consists mainly of a memory area that
  10.  * contains the frame buffer.  On the UAE side, we allocate a block of memory
  11.  * that will hold the frame buffer.  This block is in normal memory, it is
  12.  * never directly on the graphics card.  All graphics operations, which are
  13.  * mainly reads and writes into this block and a few basic operations like
  14.  * filling a rectangle, operate on this block of memory.
  15.  * Since the memory is not on the graphics card, some work must be done to
  16.  * synchronize the display with the data in the Picasso frame buffer.  There
  17.  * are various ways to do this.  One possibility is to allocate a second
  18.  * buffer of the same size, and perform all write operations twice.  Since
  19.  * we never read from the second buffer, it can actually be placed in video
  20.  * memory.  The X11 driver could be made to use the Picasso frame buffer as
  21.  * the data buffer of an XImage, which could then be XPutImage()d from time
  22.  * to time.  Another possibility is to translate all Picasso accesses into
  23.  * Xlib (or GDI, or whatever your graphics system is) calls.  This possibility
  24.  * is a bit tricky, since there is a risk of generating very many single pixel
  25.  * accesses which may be rather slow.
  26.  *
  27.  * TODO:
  28.  * - add an 8 bit emulation for hicolor/truecolor screens. This would allow
  29.  *   users to select an 8 bit Workbench resolution that would work regardless
  30.  *   of which color depth the display is currently in.
  31.  * - add panning capability
  32.  */
  33.  
  34. #include "sysconfig.h"
  35. #include "sysdeps.h"
  36.  
  37. #include "config.h"
  38. #include "options.h"
  39. #include "threaddep/penguin.h"
  40. #include "uae.h"
  41. #include "memory.h"
  42. #include "custom.h"
  43. #include "readcpu.h"
  44. #include "newcpu.h"
  45. #include "xwin.h"
  46. #include "picasso96.h"
  47.  
  48. #ifdef PICASSO96
  49.  
  50. extern uae_u8 *lockscr (void);
  51. extern void unlockscr (void);
  52.  
  53. #define MyOutputDebugString printf
  54.  
  55. static uae_u32 gfxmem_lget (uaecptr) REGPARAM;
  56. static uae_u32 gfxmem_wget (uaecptr) REGPARAM;
  57. static uae_u32 gfxmem_bget (uaecptr) REGPARAM;
  58. static void gfxmem_lput (uaecptr, uae_u32) REGPARAM;
  59. static void gfxmem_wput (uaecptr, uae_u32) REGPARAM;
  60. static void gfxmem_bput (uaecptr, uae_u32) REGPARAM;
  61. static int gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM;
  62. static uae_u8 *gfxmem_xlate (uaecptr addr) REGPARAM;
  63.  
  64. static void write_gfx_long (uaecptr addr, uae_u32 value);
  65. static void write_gfx_word (uaecptr addr, uae_u16 value);
  66. static void write_gfx_byte (uaecptr addr, uae_u8 value);
  67.  
  68. static uae_u8 all_ones_bitmap, all_zeros_bitmap; /* yuk */
  69.  
  70. struct picasso96_state_struct picasso96_state;
  71. struct picasso_vidbuf_description picasso_vidinfo;
  72.  
  73. /* These are the maximum resolutions... They are filled in by GetSupportedResolutions() */
  74. /* have to fill this in, otherwise problems occur
  75.  * @@@ ??? what problems?
  76.  */
  77. struct ScreenResolution planar = { 320, 240 };
  78. struct ScreenResolution chunky = { 640, 480 };
  79. struct ScreenResolution hicolour = { 640, 480 };
  80. struct ScreenResolution truecolour = { 640, 480 };
  81. struct ScreenResolution alphacolour = { 460, 480 };
  82.  
  83. uae_u16 picasso96_pixel_format = RGBFF_CHUNKY;
  84.  
  85. struct PicassoResolution DisplayModes[MAX_PICASSO_MODES];
  86.  
  87. static int mode_count = 0;
  88.  
  89. static uae_u32 p2ctab[256][2];
  90.  
  91. /*
  92.  * Debugging dumps
  93.  */
  94.  
  95. static void DumpModeInfoStructure (uaecptr amigamodeinfoptr)
  96. {
  97.     int i;
  98.     MyOutputDebugString ("ModeInfo Structure Dump:\n");
  99.     MyOutputDebugString ("  Node.ln_Succ  = 0x%x\n", get_long (amigamodeinfoptr));
  100.     MyOutputDebugString ("  Node.ln_Pred  = 0x%x\n", get_long (amigamodeinfoptr + 4));
  101.     MyOutputDebugString ("  Node.ln_Type  = 0x%x\n", get_byte (amigamodeinfoptr + 8));
  102.     MyOutputDebugString ("  Node.ln_Pri   = %d\n", get_byte (amigamodeinfoptr + 9));
  103.     /*MyOutputDebugString ("  Node.ln_Name  = %s\n", uaememptr->Node.ln_Name); */
  104.     MyOutputDebugString ("  OpenCount     = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount));
  105.     MyOutputDebugString ("  Active        = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active));
  106.     MyOutputDebugString ("  Width         = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width));
  107.     MyOutputDebugString ("  Height        = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height));
  108.     MyOutputDebugString ("  Depth         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth));
  109.     MyOutputDebugString ("  Flags         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags));
  110.     MyOutputDebugString ("  HorTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal));
  111.     MyOutputDebugString ("  HorBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize));
  112.     MyOutputDebugString ("  HorSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart));
  113.     MyOutputDebugString ("  HorSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize));
  114.     MyOutputDebugString ("  HorSyncSkew   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew));
  115.     MyOutputDebugString ("  HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew));
  116.     MyOutputDebugString ("  VerTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal));
  117.     MyOutputDebugString ("  VerBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize));
  118.     MyOutputDebugString ("  VerSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart));
  119.     MyOutputDebugString ("  VerSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize));
  120.     MyOutputDebugString ("  Clock         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union));
  121.     MyOutputDebugString ("  ClockDivide   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union));
  122.     MyOutputDebugString ("  PixelClock    = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock));
  123. }
  124.  
  125. static void DumpLibResolutionStructure (uaecptr amigalibresptr)
  126. {
  127.     int i;
  128.     uaecptr amigamodeinfoptr;
  129.     struct LibResolution *uaememptr = (struct LibResolution *)get_mem_bank(amigalibresptr).xlateaddr(amigalibresptr);
  130.     
  131.     return;
  132.  
  133.     MyOutputDebugString ("LibResolution Structure Dump:\n");
  134.  
  135.     if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) {
  136.     MyOutputDebugString ("  Finished With LibResolutions...\n");
  137.     } else {
  138.     MyOutputDebugString ("  Name      = %s\n", uaememptr->P96ID);
  139.     MyOutputDebugString ("  DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID));
  140.     MyOutputDebugString ("  Width     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width));
  141.     MyOutputDebugString ("  Height    = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height));
  142.     MyOutputDebugString ("  Flags     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags));
  143.     for (i = 0; i < MAXMODES; i++) {
  144.         amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i*4);
  145.         MyOutputDebugString ("  ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr);
  146.         if (amigamodeinfoptr)
  147.         DumpModeInfoStructure(amigamodeinfoptr);
  148.     }
  149.     MyOutputDebugString ("  BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo));
  150.     }
  151. }
  152.  
  153. static char binary_byte[8];
  154.  
  155. static char *BuildBinaryString (uae_u8 value)
  156. {
  157.     int i;
  158.     for (i = 0; i < 8; i++) {
  159.     binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.';
  160.     }
  161.     return binary_byte;
  162. }
  163.  
  164. static void DumpPattern (struct Pattern *patt)
  165. {
  166.     uae_u8 *mem;
  167.     int row, col;
  168.     for (row = 0; row < (1 << patt->Size); row++) {
  169.     mem = patt->Memory + row * 2;
  170.     for (col = 0; col < 2; col++) {
  171.         MyOutputDebugString ("%s", BuildBinaryString (*mem++));
  172.     }
  173.     MyOutputDebugString ("\n");
  174.     }
  175. }
  176.  
  177. static void DumpTemplate (struct Template *tmp, uae_u16 w, uae_u16 h)
  178. {
  179.     uae_u8 *mem = tmp->Memory;
  180.     int row, col, width;
  181.     width = (w + 7) >> 3;
  182.     MyOutputDebugString ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow);
  183.     for (row = 0; row < h; row++) {
  184.     mem = tmp->Memory + row * tmp->BytesPerRow;
  185.     for (col = 0; col < width; col++) {
  186.         MyOutputDebugString ("%s", BuildBinaryString (*mem++));
  187.     }
  188.     MyOutputDebugString ("\n");
  189.     }
  190. }
  191.  
  192. static void ShowSupportedResolutions (void)
  193. {
  194.     int i;
  195.     
  196.     return;
  197.  
  198.     for (i = 0; i < mode_count; i++)
  199.     MyOutputDebugString ("%s\n", DisplayModes[i].name);
  200. }
  201.  
  202. /*
  203.  * Amiga <-> native structure conversion functions
  204.  */
  205.  
  206. static int CopyRenderInfoStructureA2U (uaecptr amigamemptr, struct RenderInfo *ri)
  207. {
  208.     uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory);
  209.  
  210.     if (valid_address (memp, 1 /* FIXME */)) {
  211.     ri->Memory = get_real_address (memp);
  212.     ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow);
  213.     ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat);
  214.     return 1;
  215.     }
  216.     MyOutputDebugString ("ERROR - Invalid RenderInfo memory area...\n");
  217.     return 0;
  218. }
  219.  
  220. static int CopyPatternStructureA2U (uaecptr amigamemptr, struct Pattern *pattern)
  221. {
  222.     uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory);
  223.     if (valid_address (memp, 1 /* FIXME */)) {
  224.     pattern->Memory = get_real_address (memp);
  225.     pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset);
  226.     pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset);
  227.     pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen);
  228.     pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen);
  229.     pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size);
  230.     pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode);
  231.     return 1;
  232.     }
  233.     MyOutputDebugString ("ERROR - Invalid Pattern memory area...\n");
  234.     return 0;
  235. }
  236.  
  237. static void CopyColorIndexMappingA2U (uaecptr amigamemptr, struct ColorIndexMapping *cim)
  238. {
  239.     int i;
  240.     cim->ColorMask = get_long (amigamemptr);
  241.     for (i = 0; i < 256; i++, amigamemptr += 4)
  242.     cim->Colors[i] = get_long (amigamemptr + 4);
  243. }
  244.  
  245. static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm)
  246. {
  247.     int i;
  248.  
  249.     bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow);
  250.     bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows);
  251.     bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags);
  252.     bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth);
  253.  
  254.     for (i = 0; i < bm->Depth; i++) {
  255.     uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i*4);
  256.     switch (plane) {
  257.      case 0:
  258.         bm->Planes[i] = &all_zeros_bitmap;
  259.         break;
  260.      case 0xFFFFFFFF:
  261.         bm->Planes[i] = &all_ones_bitmap;
  262.         break;
  263.      default:
  264.         if (valid_address (plane, bm->BytesPerRow * bm->Rows))
  265.         bm->Planes[i] = get_real_address (plane);
  266.         else
  267.         return 0;
  268.         break;
  269.     }
  270.     }
  271.     return 1;
  272. }
  273.  
  274. static int CopyTemplateStructureA2U (uaecptr amigamemptr, struct Template *tmpl)
  275. {
  276.     uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory);
  277.  
  278.     if (valid_address (memp, 1 /* FIXME */)) {
  279.     tmpl->Memory = get_real_address (memp);
  280.     tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow);
  281.     tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset);
  282.     tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode);
  283.     tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen);
  284.     tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen);
  285.     return 1;
  286.     }
  287.     MyOutputDebugString ("ERROR - Invalid Template memory area...\n");
  288.     return 0;
  289. }
  290.  
  291. static void CopyLibResolutionStructureU2A (struct LibResolution *libres, uaecptr amigamemptr)
  292. {
  293.     char *uaememptr = 0;
  294.     int i;
  295.  
  296.     uaememptr = gfxmem_xlate(amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
  297.     memset(uaememptr, 0, PSSO_LibResolution_sizeof); /* zero out our LibResolution structure */
  298.     strcpy(uaememptr + PSSO_LibResolution_P96ID, libres->P96ID);
  299.     put_long(amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID);
  300.     put_word(amigamemptr + PSSO_LibResolution_Width, libres->Width);
  301.     put_word(amigamemptr + PSSO_LibResolution_Height, libres->Height);
  302.     put_word(amigamemptr + PSSO_LibResolution_Flags, libres->Flags);
  303.     for (i = 0; i < MAXMODES; i++)
  304.     put_long(amigamemptr + PSSO_LibResolution_Modes + i*4, libres->Modes[i]);
  305. #if 0
  306.     put_long(amigamemptr, libres->Node.ln_Succ);
  307.     put_long(amigamemptr + 4, libres->Node.ln_Pred);
  308.     put_byte(amigamemptr + 8, libres->Node.ln_Type);
  309.     put_byte(amigamemptr + 9, libres->Node.ln_Pri);
  310. #endif
  311.     put_long(amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID);
  312.     put_long(amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo);
  313. }
  314.  
  315. /* list is Amiga address of list, in correct endian format for UAE
  316.  * node is Amiga address of node, in correct endian format for UAE */
  317. static void AmigaListAddTail (uaecptr list, uaecptr node)
  318. {
  319.     uaecptr amigamemptr = 0;
  320.  
  321.     if (get_long (list + 8) == list) {
  322.     /* Empty list - set it up */
  323.     put_long(list, node);     /* point the lh_Head to our new node */
  324.     put_long(list + 4, 0);    /* set the lh_Tail to NULL */
  325.     put_long(list + 8, node); /* point the lh_TailPred to our new node */
  326.  
  327.     /* Adjust the new node - don't rely on it being zeroed out */
  328.     put_long(node, 0); /* ln_Succ */
  329.     put_long(node + 4, 0); /* ln_Pred */
  330.     } else {
  331.     amigamemptr = get_long (list + 8); /* get the lh_TailPred contents */
  332.  
  333.     put_long(list + 8, node); /* point the lh_TailPred to our new node */
  334.  
  335.     /* Adjust the previous lh_TailPred node */
  336.     put_long(amigamemptr, node); /* point the ln_Succ to our new node */
  337.  
  338.     /* Adjust the new node - don't rely on it being zeroed out */
  339.     put_long(node, 0); /* ln_Succ */
  340.     put_long(node + 4, amigamemptr); /* ln_Pred */
  341.     }
  342. }
  343.  
  344. /*
  345.  * Functions to perform an action on the real screen
  346.  */
  347.  
  348. /*
  349.  * Fill a rectangle on the screen.  src points to the start of a line of the
  350.  * filled rectangle in the frame buffer; it can be used as a memcpy source if
  351.  * there is no OS specific function to fill the rectangle.
  352.  */
  353.  
  354. static void do_fillrect (uae_u8 *src, int x, int y, int width, int height)
  355. {
  356.     int lines;
  357.     uae_u8 *dst;
  358.     /* Try OS specific fillrect function here; and return if successful.  */
  359.  
  360.     DX_Invalidate (y, y + height - 1);
  361.     if (! picasso_vidinfo.extra_mem)
  362.     return;
  363.  
  364.     width *= picasso96_state.BytesPerPixel;
  365.     dst = lockscr ();
  366.     if (!dst)
  367.     return;
  368.  
  369.     dst += y*picasso_vidinfo.rowbytes + x*picasso96_state.BytesPerPixel;
  370.     while (height-- > 0) {
  371.     memcpy (dst, src, width);
  372.     dst += picasso_vidinfo.rowbytes;
  373.     }
  374.     unlockscr ();
  375. }
  376.  
  377. /*
  378.  * This routine modifies the real screen buffer after a blit has been
  379.  * performed in the save area. If can_do_blit is nonzero, the blit can
  380.  * be performed within the real screen buffer; otherwise, this routine
  381.  * must do it by hand using the data in the save area, pointed to by
  382.  * srcp.
  383.  */
  384.  
  385. static void do_blit (uae_u8 *srcp, unsigned long src_rowbytes,
  386.              int srcx, int srcy, int dstx, int dsty,
  387.              int width, int height, int can_do_blit)
  388. {
  389.     uae_u8 *dstp;
  390.     /* If this RenderInfo points at something else than the currently visible
  391.      * screen, we must ignore the blit.  */
  392.     if (can_do_blit) {
  393.     /*
  394.      * Call OS blitting function that can do it in video memory.
  395.      * Should return if it was successful
  396.      */
  397.     }
  398.  
  399.     DX_Invalidate (dsty, dsty + height - 1);
  400.     if (! picasso_vidinfo.extra_mem)
  401.     return;
  402.  
  403.     width *= picasso96_state.BytesPerPixel;
  404.     dstp = lockscr ();
  405.     if (dstp == 0)
  406.     return;
  407.  
  408.     /* The areas can't overlap: the source is always in the Picasso frame buffer,
  409.      * and the destination is a different buffer owned by the graphics code.  */
  410.  
  411.     dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso96_state.BytesPerPixel;
  412.     while (height-- > 0) {
  413.     memcpy (dstp, srcp, width);
  414.     srcp += src_rowbytes;
  415.     dstp += picasso_vidinfo.rowbytes;
  416.     }
  417.     unlockscr ();
  418. }
  419.  
  420. /*
  421.  * Invert a rectangle on the screen.  src and src_rowbytes describe the
  422.  * inverted rectangle in the frame buffer, so that do_blit can be used if
  423.  * there is no OS specific function to fill the rectangle.
  424.  */
  425.  
  426. static void do_invertrect (uae_u8 *src, unsigned long src_rowbytes,
  427.                int x, int y, int width, int height)
  428. {
  429.     /* Try OS specific invertrect function here; and return if successful.  */
  430.  
  431.     do_blit (src, src_rowbytes, 0, 0, x, y, width, height, 0);
  432. }
  433.  
  434. static uaecptr wgfx_linestart;
  435. static uaecptr wgfx_lineend;
  436. static uaecptr wgfx_min, wgfx_max;
  437. static unsigned long wgfx_y;
  438.  
  439. static void wgfx_do_flushline (void)
  440. {
  441.     uae_u8 *src, *dstp;
  442.  
  443.     DX_Invalidate (wgfx_y, wgfx_y);
  444.     if (! picasso_vidinfo.extra_mem)
  445.     goto out;
  446.  
  447.     dstp = lockscr ();
  448.     if (dstp == 0)
  449.     goto out;
  450.     /*printf("flushing %d (%x %x %x)\n", wgfx_y, wgfx_linestart, wgfx_min, wgfx_max); */
  451.     src = (gfxmemory + wgfx_min);
  452.  
  453.     dstp += wgfx_y * picasso_vidinfo.rowbytes + wgfx_min - wgfx_linestart;
  454.     memcpy (dstp, src, wgfx_max - wgfx_min);
  455.     unlockscr ();
  456.  
  457.     out:
  458.     wgfx_linestart = 0xFFFFFFFF;
  459. }
  460.  
  461. static __inline__ void wgfx_flushline (void)
  462. {
  463.     if (wgfx_linestart == 0xFFFFFFFF)
  464.     return;
  465.     wgfx_do_flushline ();
  466. }
  467.  
  468.  
  469. static int renderinfo_is_current_screen (struct RenderInfo *ri)
  470. {
  471.     if (! picasso_on)
  472.     return 0;
  473.     if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start)) {
  474.     return 0;
  475.     }
  476.     return 1;
  477. }
  478.  
  479. /* Clear our screen, since we've got a new Picasso screen-mode, and refresh with the proper contents
  480.  * NOTE: This is called in two cases:
  481.  *       1. Amiga-->Picasso transition, via SetSwitch()
  482.  *       2. Picasso-->Picasso transition, via SetPanning().  */
  483. static void picasso_refresh (void)
  484. {
  485.     struct RenderInfo ri;
  486.  
  487.     if (! picasso_on)
  488.     return;
  489.  
  490.     /* Make sure that the first time we show a Picasso video mode, we don't blit any crap.
  491.      * We can do this by checking if we have an Address yet.  */
  492.     if (picasso96_state.Address) {
  493.     /* blit the stuff from our static frame-buffer to the gfx-card */
  494.     uae_u8 *ptr = gfxmemory + (picasso96_state.Address - gfxmem_start);
  495.     ri.BytesPerRow = picasso96_state.BytesPerRow;
  496.     ri.RGBFormat = picasso96_state.RGBFormat;
  497.     do_blit (ptr, picasso96_state.BytesPerRow, 0, 0, 0, 0,
  498.          picasso96_state.Width, picasso96_state.Height, 0);
  499.     MyOutputDebugString ("picasso_refresh() successful.\n");
  500.     } else
  501.     MyOutputDebugString ("ERROR - picasso_refresh() can't refresh!\n");
  502. }
  503.  
  504. /*
  505.  * BOOL FindCard(struct BoardInfo *bi);       and
  506.  *
  507.  * FindCard is called in the first stage of the board initialisation and
  508.  * configuration and is used to look if there is a free and unconfigured
  509.  * board of the type the driver is capable of managing. If it finds one,
  510.  * it immediately reserves it for use by Picasso96, usually by clearing
  511.  * the CDB_CONFIGME bit in the flags field of the ConfigDev struct of
  512.  * this expansion card. But this is only a common example, a driver can
  513.  * do whatever it wants to mark this card as used by the driver. This
  514.  * mechanism is intended to ensure that a board is only configured and
  515.  * used by one driver. FindBoard also usually fills some fields of the
  516.  * BoardInfo struct supplied by the caller, the rtg.library, for example
  517.  * the MemoryBase, MemorySize and RegisterBase fields.
  518.  */
  519. uae_u32 picasso_FindCard (void)
  520. {
  521.     int loop;
  522.     uaecptr AmigaBoardInfo = m68k_areg(regs, 0);
  523.     /* NOTES: See BoardInfo struct definition in Picasso96 dev info */
  524.  
  525.     if (gfxmem_size && !picasso96_state.CardFound) {
  526.     /* Fill in MemoryBase, MemorySize */
  527.     put_long(AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start);
  528.     /* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for resolution list */
  529.     put_long(AmigaBoardInfo + PSSO_BoardInfo_MemorySize, gfxmem_size - 32768);
  530.  
  531.     picasso96_state.CardFound = 1; /* mark our "card" as being found */
  532.     return -1;
  533.     } else
  534.     return 0;
  535. }
  536.  
  537. static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res, struct PicassoResolution *dm)
  538. {
  539.     char *uaememptr;
  540.     switch (dm->depth) {
  541.     case 1:
  542.     res->Modes[CHUNKY] = amigamemptr;
  543.     break;
  544.     case 2:
  545.     res->Modes[HICOLOR] = amigamemptr;
  546.     break;
  547.     case 3:
  548.     res->Modes[TRUECOLOR] = amigamemptr;
  549.     break;
  550.     default:
  551.     res->Modes[TRUEALPHA] = amigamemptr;
  552.     break;
  553.     }
  554.     uaememptr = gfxmem_xlate(amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
  555.     memset(uaememptr, 0, PSSO_ModeInfo_sizeof); /* zero out our ModeInfo struct */
  556.  
  557.     put_word(amigamemptr + PSSO_ModeInfo_Width, dm->res.width);
  558.     put_word(amigamemptr + PSSO_ModeInfo_Height, dm->res.height);
  559.     put_byte(amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8);
  560.     put_byte(amigamemptr + PSSO_ModeInfo_Flags, 0);
  561.     put_word(amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width);
  562.     put_word(amigamemptr + PSSO_ModeInfo_HorBlankSize, 0);
  563.     put_word(amigamemptr + PSSO_ModeInfo_HorSyncStart, 0);
  564.     put_word(amigamemptr + PSSO_ModeInfo_HorSyncSize, 0);
  565.     put_byte(amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0);
  566.     put_byte(amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0);
  567.  
  568.     put_word(amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height);
  569.     put_word(amigamemptr + PSSO_ModeInfo_VerBlankSize, 0);
  570.     put_word(amigamemptr + PSSO_ModeInfo_VerSyncStart, 0);
  571.     put_word(amigamemptr + PSSO_ModeInfo_VerSyncSize, 0);
  572.  
  573.     put_byte(amigamemptr + PSSO_ModeInfo_first_union, 98);
  574.     put_byte(amigamemptr + PSSO_ModeInfo_second_union, 14);
  575.  
  576.     put_long(amigamemptr + PSSO_ModeInfo_PixelClock, dm->res.width * dm->res.height * dm->refresh);
  577. }
  578.  
  579. /****************************************
  580. * InitCard()
  581. *
  582. * a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format
  583. *
  584. * Job - fill in the following structure members:
  585. * gbi_RGBFormats: the pixel formats that the host-OS of UAE supports
  586. *     If UAE is running in a window, it should ONLY report the pixel format of the host-OS desktop
  587. *     If UAE is running full-screen, it should report ALL pixel formats that the host-OS can handle in full-screen
  588. *     NOTE: If full-screen, and the user toggles to windowed-mode, all hell will break loose visually.  Must inform
  589. *           user that they're doing something stupid (unless their desktop and full-screen colour modes match).
  590. * gbi_SoftSpriteFlags: should be the same as above for now, until actual cursor support is added
  591. * gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card
  592. * gbi_MaxHorResolution: fill this in for all modes (even if you don't support them)
  593. * gbi_MaxVerResolution: fill this in for all modes (even if you don't support them)
  594. */
  595. uae_u32 picasso_InitCard (void)
  596. {
  597.     struct LibResolution res;
  598.     int i;
  599.     int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0;
  600.     uaecptr amigamemptr = 0;
  601.     uaecptr AmigaBoardInfo = m68k_areg(regs, 2);
  602.     put_word(AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon());
  603.     put_word(AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format);
  604.     put_word(AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format);
  605.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width);
  606.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width);
  607.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width);
  608.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width);
  609.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width);
  610.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height);
  611.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height);
  612.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height);
  613.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height);
  614.     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height);
  615.  
  616.     for (i = 0; i < mode_count;) {
  617.     int j = i;
  618.     /* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */
  619.     res.DisplayID = 0x50001000 + LibResolutionStructureCount * 0x10000;
  620.     res.BoardInfo = AmigaBoardInfo;
  621.     res.Width = DisplayModes[i].res.width;
  622.     res.Height = DisplayModes[i].res.height;
  623.     res.Flags = P96F_PUBLIC;
  624.     res.P96ID[0] = 'P';
  625.     res.P96ID[1] = '9';
  626.     res.P96ID[2] = '6';
  627.     res.P96ID[3] = '-';
  628.     res.P96ID[4] = '0';
  629.     res.P96ID[5] = ':';
  630.     strcpy (res.Name, "uaegfx:");
  631.     strncat (res.Name, DisplayModes[i].name, strchr(DisplayModes[i].name, ',') - DisplayModes[i].name);
  632.     res.Modes[PLANAR] = 0;
  633.     res.Modes[CHUNKY] = 0;
  634.     res.Modes[HICOLOR] = 0;
  635.     res.Modes[TRUECOLOR] = 0;
  636.     res.Modes[TRUEALPHA] = 0;
  637.  
  638.     do {
  639.         /* Handle this display mode's depth */
  640.         amigamemptr = gfxmem_start + gfxmem_size - (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++);
  641.         FillBoardInfo(amigamemptr, &res, &DisplayModes[i]);
  642.         i++;
  643.     } while (i < mode_count
  644.          && DisplayModes[i].res.width == DisplayModes[j].res.width
  645.          && DisplayModes[i].res.height == DisplayModes[j].res.height);
  646.  
  647.     amigamemptr = gfxmem_start + gfxmem_size - 16384 + (PSSO_LibResolution_sizeof * LibResolutionStructureCount++);
  648.     CopyLibResolutionStructureU2A (&res, amigamemptr);
  649.     DumpLibResolutionStructure( amigamemptr);
  650.     AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr);
  651.     }
  652.  
  653.     return 0;
  654. }
  655.  
  656. extern int x_size, y_size;
  657.  
  658. /*
  659.  * SetSwitch:
  660.  * a0:    struct BoardInfo
  661.  * d0.w:    BOOL state
  662.  * this function should set a board switch to let the Amiga signal pass
  663.  * through when supplied with a 0 in d0 and to show the board signal if
  664.  * a 1 is passed in d0. You should remember the current state of the
  665.  * switch to avoid unneeded switching. If your board has no switch, then
  666.  * simply supply a function that does nothing except a RTS.
  667.  *
  668.  * NOTE: Return the opposite of the switch-state. BDK
  669. */
  670. uae_u32 picasso_SetSwitch (void)
  671. {
  672.     uae_u16 flag = m68k_dreg(regs, 0) & 0xFFFF;
  673.     uae_u32 result;
  674.  
  675.     /* Do not switch immediately.  Tell the custom chip emulation about the
  676.      * desired state, and wait for custom.c to call picasso_enablescreen
  677.      * whenever it is ready to change the screen state.  */
  678.     picasso_requested_on = !!flag;
  679.     MyOutputDebugString ("SetSwitch() - trying to show %s screen\n", flag ? "picasso96":"amiga");
  680.  
  681.     /* Put old switch-state in D0 */
  682.     return !flag;
  683. }
  684.  
  685. void picasso_enablescreen (int on)
  686. {
  687.     wgfx_linestart = 0xFFFFFFFF;
  688.     picasso_refresh ();
  689.     MyOutputDebugString ("SetSwitch() - showing %s screen\n", on ? "picasso96":"amiga");
  690. }
  691.  
  692. /*
  693.  * SetColorArray:
  694.  * a0: struct BoardInfo
  695.  * d0.w: startindex
  696.  * d1.w: count
  697.  * when this function is called, your driver has to fetch "count" color
  698.  * values starting at "startindex" from the CLUT field of the BoardInfo
  699.  * structure and write them to the hardware. The color values are always
  700.  * between 0 and 255 for each component regardless of the number of bits
  701.  * per cannon your board has. So you might have to shift the colors
  702.  * before writing them to the hardware.
  703.  */
  704. uae_u32 picasso_SetColorArray (void)
  705. {
  706.     /* Fill in some static UAE related structure about this new CLUT setting
  707.      * We need this for CLUT-based displays, and for mapping CLUT to hi/true colour */
  708.     uae_u16 start = m68k_dreg(regs, 0);
  709.     uae_u16 count = m68k_dreg(regs, 1);
  710.     int i;
  711.     uaecptr boardinfo = m68k_areg(regs, 0);
  712.     uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3;
  713.  
  714.     for (i = start; i < start + count; i++) {
  715.     picasso96_state.CLUT[i].Red = get_byte (clut);
  716.     picasso96_state.CLUT[i].Green = get_byte (clut + 1);
  717.     picasso96_state.CLUT[i].Blue = get_byte (clut + 2);
  718.     clut += 3;
  719.     }
  720.     DX_SetPalette(start, count);
  721.     /*MyOutputDebugString ("SetColorArray(%d,%d)\n", start, count); */
  722.     return m68k_dreg(regs, 0);
  723. }
  724.  
  725. static uae_u8 GetBytesPerPixel(uae_u32 RGBfmt)
  726. {
  727.     switch (RGBfmt) {
  728.      case RGBFB_CLUT:
  729.     return 1;
  730.  
  731.      case RGBFB_A8R8G8B8:
  732.      case RGBFB_A8B8G8R8:
  733.      case RGBFB_R8G8B8A8:
  734.      case RGBFB_B8G8R8A8:
  735.     return 4;
  736.  
  737.      case RGBFB_B8G8R8:
  738.      case RGBFB_R8G8B8:
  739.     return 3;
  740.  
  741.      case RGBFB_R5G5B5:
  742.      case RGBFB_R5G6B5:
  743.      case RGBFB_R5G6B5PC:
  744.      case RGBFB_R5G5B5PC:
  745.      case RGBFB_B5G6R5PC:
  746.      case RGBFB_B5G5R5PC:
  747.     return 2;
  748.      default:
  749.     MyOutputDebugString ("ERROR - GetBytesPerPixel() was unsuccessful with 0x%x?!\n", RGBfmt);
  750.     return 0;
  751.     }
  752. }
  753.  
  754. /*
  755.  * SetDAC:
  756.  * a0: struct BoardInfo
  757.  * d7: RGBFTYPE RGBFormat
  758.  * This function is called whenever the RGB format of the display changes,
  759.  * e.g. from chunky to TrueColor. Usually, all you have to do is to set
  760.  * the RAMDAC of your board accordingly.
  761.  */
  762. uae_u32 picasso_SetDAC (void)
  763. {
  764.     /* Fill in some static UAE related structure about this new DAC setting
  765.      * Lets us keep track of what pixel format the Amiga is thinking about in our frame-buffer */
  766.  
  767.     MyOutputDebugString ("SetDAC()\n");
  768.     return m68k_dreg(regs, 0);
  769. }
  770.  
  771. /*
  772.  * SetGC:
  773.  * a0: struct BoardInfo
  774.  * a1: struct ModeInfo
  775.  * d0: BOOL Border
  776.  * This function is called whenever another ModeInfo has to be set. This
  777.  * function simply sets up the CRTC and TS registers to generate the
  778.  * timing used for that screen mode. You should not set the DAC, clocks
  779.  * or linear start adress. They will be set when appropriate by their
  780.  * own functions.
  781.  */
  782. uae_u32 picasso_SetGC (void)
  783. {
  784.     /* Fill in some static UAE related structure about this new ModeInfo setting */
  785.     uaecptr modeinfo = m68k_areg(regs, 1);
  786.  
  787.     picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width);
  788.     picasso96_state.VirtualWidth = picasso96_state.Width; /* in case SetPanning doesn't get called */
  789.  
  790.     picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height);
  791.     picasso96_state.VirtualHeight = picasso96_state.Height;
  792.  
  793.     picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth);
  794.     picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags);
  795.  
  796.     MyOutputDebugString ("SetGC(%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height, picasso96_state.GC_Depth);
  797.  
  798.     gfx_set_picasso_modeinfo (picasso96_state.Width, picasso96_state.Height,
  799.                   picasso96_state.GC_Depth);
  800.     wgfx_linestart = 0xFFFFFFFF;
  801.     picasso_refresh ();
  802.  
  803.     return m68k_dreg(regs, 0);
  804. }
  805.  
  806. /*
  807.  * SetPanning:
  808.  * a0: struct BoardInfo
  809.  * a1: UBYTE *Memory
  810.  * d0: uae_u16 Width
  811.  * d1: WORD XOffset
  812.  * d2: WORD YOffset
  813.  * d7: RGBFTYPE RGBFormat
  814.  * This function sets the view origin of a display which might also be
  815.  * overscanned. In register a1 you get the start address of the screen
  816.  * bitmap on the Amiga side. You will have to subtract the starting
  817.  * address of the board memory from that value to get the memory start
  818.  * offset within the board. Then you get the offset in pixels of the
  819.  * left upper edge of the visible part of an overscanned display. From
  820.  * these values you will have to calculate the LinearStartingAddress
  821.  * fields of the CRTC registers.
  822.  
  823.  * NOTE: SetPanning() can be used to know when a Picasso96 screen is
  824.  * being opened.  Better to do the appropriate clearing of the
  825.  * background here than in SetSwitch() derived functions,
  826.  * because SetSwitch() is not called for subsequent Picasso screens.
  827.  */
  828. uae_u32 picasso_SetPanning (void)
  829. {
  830.     uae_u16 Width = m68k_dreg(regs, 0);
  831.     uaecptr start_of_screen = m68k_areg(regs, 1);
  832.  
  833.     picasso96_state.Address = start_of_screen; /* Amiga-side address */
  834.     picasso96_state.XOffset = (uae_s16)m68k_dreg(regs, 1);
  835.     picasso96_state.YOffset = (uae_s16)m68k_dreg(regs, 2);
  836.     picasso96_state.VirtualWidth = Width;
  837.     picasso96_state.RGBFormat = m68k_dreg(regs, 7);
  838.     picasso96_state.BytesPerPixel = GetBytesPerPixel(picasso96_state.RGBFormat);
  839.     picasso96_state.BytesPerRow = Width * picasso96_state.BytesPerPixel;
  840.  
  841.     /* I assume SetGC() has been called, so I can calculate the Extent */
  842.     picasso96_state.Extent = picasso96_state.Address + (picasso96_state.BytesPerRow * picasso96_state.Height);
  843.  
  844.     MyOutputDebugString ("SetPanning(%d, %d, %d) Start 0x%x, BPR %d\n",
  845.             Width,picasso96_state.XOffset, picasso96_state.YOffset,
  846.             start_of_screen, picasso96_state.BytesPerRow);
  847.     DX_SetPalette(0, 256);
  848.  
  849.     wgfx_linestart = 0xFFFFFFFF;
  850.     picasso_refresh ();
  851.  
  852.     return m68k_dreg(regs, 0);
  853. }
  854.  
  855. static void do_xor8 (uae_u8 *ptr, long len, uae_u32 val)
  856. {
  857.     int i;
  858. #if 0 && defined ALIGN_POINTER_TO32
  859.     int align_adjust = ALIGN_POINTER_TO32(ptr);
  860.     int len2;
  861.  
  862.     len -= align_adjust;
  863.     while (align_adjust) {
  864.     *ptr ^= val;
  865.     ptr++;
  866.     align_adjust--;
  867.     }
  868.     len2 = len >> 2;
  869.     len -= len2 << 2;
  870.     for (i = 0; i < len2; i++, ptr += 4) {
  871.     *(uae_u32 *)ptr ^= val;
  872.     }
  873.     while (len) {
  874.     *ptr ^= val;
  875.     ptr++;
  876.     len--;
  877.     }
  878.     return;
  879. #endif
  880.     for (i = 0; i < len; i++, ptr++) {
  881.     do_put_mem_byte (ptr, do_get_mem_byte (ptr) ^ val);
  882.     }
  883. }
  884.  
  885. /*
  886.  * InvertRect:
  887.  * 
  888.  * Inputs:
  889.  * a0:struct BoardInfo *bi
  890.  * a1:struct RenderInfo *ri
  891.  * d0.w:X
  892.  * d1.w:Y
  893.  * d2.w:Width
  894.  * d3.w:Height
  895.  * d4.l:Mask
  896.  * d7.l:RGBFormat
  897.  * 
  898.  * This function is used to invert a rectangular area on the board. It is called by BltBitMap,
  899.  * BltPattern and BltTemplate.
  900.  */
  901. uae_u32 picasso_InvertRect (void)
  902. {
  903.     uaecptr boardinfo = m68k_areg(regs, 0);
  904.     uaecptr renderinfo = m68k_areg(regs, 1);
  905.     long X = (uae_u16)m68k_dreg(regs, 0);
  906.     long Y = (uae_u16)m68k_dreg(regs, 1);
  907.     long Width = (uae_u16)m68k_dreg(regs, 2);
  908.     long Height = (uae_u16)m68k_dreg(regs, 3);
  909.     uae_u32 mask = m68k_dreg(regs, 4);
  910.     int Bpp = GetBytesPerPixel (m68k_dreg(regs, 7));
  911.     uae_u32 xorval;
  912.     int lines;
  913.     struct RenderInfo ri;
  914.     uae_u8 *uae_mem, *rectstart;
  915.     long width_in_bytes;
  916.  
  917.     wgfx_flushline ();
  918.  
  919.     if (!CopyRenderInfoStructureA2U (renderinfo, &ri))
  920.     return 0;
  921.  
  922.     /*MyOutputDebugString ("InvertRect %d %lx\n", Bpp, (long)mask);*/
  923.  
  924.     /* ??? Brian? mask used to be 32 bit, but it appears that only 8 bit
  925.      * values are passed to this function.  This code here seems to work
  926.      * much better... */
  927.     if (mask != 0xFF && Bpp > 8) {
  928.     MyOutputDebugString ("InvertRect: not obeying mask 0x%x properly with Bpp %d.\n", mask, Bpp);
  929.     mask = 0xFF;
  930.     }
  931.     if ((mask & ~0xFF) != 0) {
  932.     MyOutputDebugString ("InvertRect: mask has high bits set!\n");
  933.     }
  934.     xorval = 0x01010101 * (mask & 0xFF);
  935.     width_in_bytes = Bpp * Width;
  936.     rectstart = uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
  937.  
  938.     for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow) {
  939.     int j;
  940.     uae_u8 *start = uae_mem;
  941.     do_xor8 (uae_mem, width_in_bytes, xorval);
  942.     }
  943.     if (renderinfo_is_current_screen (&ri)) {
  944.     if (mask == 0xFF)
  945.         do_invertrect (rectstart, ri.BytesPerRow, X, Y, Width, Height);
  946.     else
  947.         do_blit (rectstart, ri.BytesPerRow, 0, 0, X, Y, Width, Height, 0);
  948.     }
  949.  
  950.     return 1; /* 1 if supported, 0 otherwise */
  951. }
  952.  
  953. /***********************************************************
  954. FillRect:
  955. ***********************************************************
  956. * a0:     struct BoardInfo *
  957. * a1:    struct RenderInfo *
  958. * d0:     WORD X
  959. * d1:     WORD Y
  960. * d2:     WORD Width
  961. * d3:     WORD Height
  962. * d4:    uae_u32 Pen
  963. * d5:    UBYTE Mask
  964. * d7:    uae_u32 RGBFormat
  965. ***********************************************************/
  966. uae_u32 picasso_FillRect (void)
  967. {
  968.     uaecptr boardinfo = m68k_areg(regs, 0);
  969.     uaecptr renderinfo = m68k_areg(regs, 1);
  970.     unsigned long X = (uae_u16)m68k_dreg(regs, 0);
  971.     unsigned long Y = (uae_u16)m68k_dreg(regs, 1);
  972.     unsigned long Width = (uae_u16)m68k_dreg(regs, 2);
  973.     unsigned long Height = (uae_u16)m68k_dreg(regs, 3);
  974.     uae_u32 Pen = m68k_dreg(regs, 4);
  975.     uae_u8 Mask = (uae_u8)m68k_dreg(regs, 5);
  976.     uae_u32 RGBFormat = m68k_dreg(regs, 7);
  977.  
  978.     uae_u8 *src, *dst;
  979.     uae_u8 *start, *oldstart;
  980.     struct RenderInfo local_ri;
  981.     unsigned long lines, cols;
  982.     int Bpp;
  983.     struct RenderInfo ri;
  984.  
  985.     wgfx_flushline ();
  986.  
  987.     if (! CopyRenderInfoStructureA2U(renderinfo, &ri) || Y == 0xFFFF)
  988.     return 0;
  989.  
  990.     if (ri.RGBFormat != RGBFormat)
  991.     MyOutputDebugString ("Weird Stuff!\n");
  992.  
  993.     Bpp = GetBytesPerPixel(RGBFormat);
  994.  
  995.     /*MyOutputDebugString ("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n",
  996.               X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask); */
  997.  
  998.     if (Mask == 0xFF) {
  999.     /* Do our virtual frame-buffer memory.  First, we do a single line fill by hand */
  1000.     oldstart = start = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
  1001.     switch (Bpp) {
  1002.      case 1:
  1003.         memset (start, Pen, Width);
  1004.         break;
  1005.      case 2:
  1006.         for (cols = 0; cols < Width; cols++) {
  1007.         do_put_mem_word ((uae_u16 *)start, Pen);
  1008.         start += 2;
  1009.         }
  1010.         break;
  1011.      case 3:
  1012.         for (cols = 0; cols < Width; cols++) {
  1013.         do_put_mem_byte (start, Pen & 0x000000FF);
  1014.         start++;
  1015.         *(uae_u16 *)(start) = (Pen & 0x00FFFF00) >> 8;
  1016.         start+=2;
  1017.         }
  1018.         break;
  1019.      case 4:
  1020.         for (cols = 0; cols < Width; cols++) {
  1021.         /**start = Pen; */
  1022.         do_put_mem_long ((uae_u32 *)start, Pen);
  1023.         start += 4;
  1024.         }
  1025.         break;
  1026.     }
  1027.     src = oldstart;
  1028.     dst = src + ri.BytesPerRow;
  1029.     /* next, we do the remaining line fills via memcpy() */
  1030.     for (lines = 0; lines < (Height - 1); lines++, dst += ri.BytesPerRow)
  1031.         memcpy(dst, src, Width * Bpp);
  1032.  
  1033.     if (renderinfo_is_current_screen (&ri)) {
  1034.         do_fillrect (src, X, Y, Width, Height);
  1035.     }
  1036.     return 1;
  1037.     }
  1038.  
  1039.     /* We get here only if Mask != 0xFF */
  1040.     if (Bpp != 1) {
  1041.     write_log ("Picasso: mask != 0xFF in truecolor mode!\n");
  1042.     return 0;
  1043.     }
  1044.     Pen &= Mask;
  1045.     Mask = ~Mask;
  1046.  
  1047.     oldstart = start = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
  1048.     for (lines = 0; lines < Height; lines++, start += ri.BytesPerRow) {
  1049.     uae_u8 *p = start;
  1050.     for (cols = 0; cols < Width; cols++) {
  1051.         uae_u32 tmpval = do_get_mem_byte (p) & Mask;
  1052.         do_put_mem_byte (p, Pen | tmpval);
  1053.         p++;
  1054.     }
  1055.     }
  1056.     if (renderinfo_is_current_screen (&ri))
  1057.     do_blit (oldstart, ri.BytesPerRow, 0, 0, X, Y, Width, Height, 0);
  1058.  
  1059.     return 1;
  1060. }
  1061.  
  1062. /*
  1063.  * BlitRect() is a generic (any chunky pixel format) rectangle copier
  1064.  * NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area, and called from picasso_BlitRect()
  1065.  */
  1066. static void BlitRect (struct RenderInfo *ri, struct RenderInfo *dstri,
  1067.               uae_u16 srcx, uae_u16 srcy, uae_u16 dstx, uae_u16 dsty,
  1068.               uae_u16 width, uae_u16 height, uae_u8 mask)
  1069. {
  1070.     uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
  1071.     int lines;
  1072.     uae_u8 Bpp = GetBytesPerPixel(ri->RGBFormat);
  1073.     uae_u8 *blitsrc;
  1074.     unsigned long total_width = width * Bpp;
  1075.     unsigned long linewidth = (total_width + 15) & ~15;
  1076.     int cant_blit = 1;
  1077.  
  1078.     /*
  1079.      * If we have no destination RenderInfo, then we're dealing with a single-buffer action, called
  1080.      * from picasso_BlitRect().  The code up to the DX_xxxxx() functions deals with the frame-buffer,
  1081.      * while the DX_ functions actually deal with the visible screen.
  1082.      *
  1083.      * If we have a destination RenderInfo, then we've been called from picasso_BlitRectNoMaskComplete()
  1084.      * and we need to put the results on the screen from the frame-buffer.
  1085.      */
  1086.     if (dstri == NULL) {
  1087.     dstri = ri;
  1088.     cant_blit = 0;
  1089.     }
  1090.  
  1091.     /* Do our virtual frame-buffer memory first */
  1092.     src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
  1093.     dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow;
  1094.     blitsrc = dst;
  1095.     if (mask != 0xFF && Bpp > 1)
  1096.     MyOutputDebugString ("ERROR - not obeying BlitRect() mask 0x%x properly with Bpp %d.\n", mask, Bpp);
  1097.  
  1098.     if (mask == 0xFF || Bpp > 1) {
  1099.     /* handle normal case efficiently */
  1100.     if (ri->Memory == dstri->Memory && dsty == srcy) {
  1101.         int i;
  1102.         for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
  1103.         memmove (dst, src, total_width);
  1104.     } else if (dsty < srcy) {
  1105.         int i;
  1106.         for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
  1107.         memcpy (dst, src, total_width);
  1108.     } else {
  1109.         int i;
  1110.         src += (height-1) * ri->BytesPerRow;
  1111.         dst += (height-1) * dstri->BytesPerRow;
  1112.         for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
  1113.         memcpy (dst, src, total_width);
  1114.     }
  1115.     if (renderinfo_is_current_screen (dstri))
  1116.         do_blit (blitsrc, dstri->BytesPerRow, srcx, srcy, dstx, dsty,
  1117.              width, height, ! cant_blit);
  1118.     return;
  1119.     }
  1120.  
  1121.     tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough memory for the src-rect */
  1122.     if (!tmp)
  1123.     return;
  1124.  
  1125.     /* copy the src-rect into our temporary buffer space */
  1126.     for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth) {
  1127.     memcpy (tmp2, src, total_width);
  1128.     }
  1129.  
  1130.     /* copy the temporary buffer to the destination */
  1131.     for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) {
  1132.     int cols;
  1133.     for (cols = 0; cols < width; cols++) {
  1134.         dst[cols] &= ~mask;
  1135.         dst[cols] |= tmp[cols] & mask;
  1136.     }
  1137.     }
  1138.     if (renderinfo_is_current_screen (dstri))
  1139.     do_blit (blitsrc, dstri->BytesPerRow, srcx, srcy, dstx, dsty,
  1140.          width, height, 0);
  1141.     /* free the temp-buf */
  1142.     free (tmp3);
  1143.  
  1144. }
  1145.  
  1146. /***********************************************************
  1147. BlitRect:
  1148. ***********************************************************
  1149. * a0:     struct BoardInfo
  1150. * a1:    struct RenderInfo
  1151. * d0:     WORD SrcX
  1152. * d1:     WORD SrcY
  1153. * d2:     WORD DstX
  1154. * d3:     WORD DstY
  1155. * d4:   WORD Width
  1156. * d5:   WORD Height
  1157. * d6:    UBYTE Mask
  1158. * d7:    uae_u32 RGBFormat
  1159. ***********************************************************/
  1160. uae_u32 picasso_BlitRect (void)
  1161. {
  1162.     uaecptr boardinfo = m68k_areg(regs, 0);
  1163.     uaecptr renderinfo = m68k_areg(regs, 1);
  1164.     uae_u16 srcx = (uae_u16)m68k_dreg(regs, 0);
  1165.     uae_u16 srcy = (uae_u16)m68k_dreg(regs, 1);
  1166.     uae_u16 dstx = (uae_u16)m68k_dreg(regs, 2);
  1167.     uae_u16 dsty = (uae_u16)m68k_dreg(regs, 3);
  1168.     uae_u16 width = (uae_u16)m68k_dreg(regs, 4);
  1169.     uae_u16 height = (uae_u16)m68k_dreg(regs, 5);
  1170.     uae_u8  Mask = (uae_u8)m68k_dreg(regs, 6);
  1171.     uae_u32 RGBFormat = m68k_dreg(regs, 7);
  1172.  
  1173.     struct RenderInfo ri;
  1174.  
  1175.     wgfx_flushline ();
  1176.  
  1177.     if (!CopyRenderInfoStructureA2U (renderinfo, &ri))
  1178.     return 0;
  1179.  
  1180.     BlitRect(&ri, NULL, srcx, srcy, dstx, dsty, width, height, Mask);
  1181.     /*MyOutputDebugString ("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask); */
  1182.  
  1183.     return 1;
  1184. }
  1185.  
  1186. /***********************************************************
  1187. BlitRectNoMaskComplete:
  1188. ***********************************************************
  1189. * a0:     struct BoardInfo
  1190. * a1:    struct RenderInfo (src)
  1191. * a2:   struct RenderInfo (dst)
  1192. * d0:     WORD SrcX
  1193. * d1:     WORD SrcY
  1194. * d2:     WORD DstX
  1195. * d3:     WORD DstY
  1196. * d4:   WORD Width
  1197. * d5:   WORD Height
  1198. * d6:    UBYTE OpCode
  1199. * d7:    uae_u32 RGBFormat
  1200. * NOTE: MUST return 0 in D0 if we're not handling this operation
  1201. *       because the RGBFormat or opcode aren't supported.
  1202. *       OTHERWISE return 1
  1203. ***********************************************************/
  1204. uae_u32 picasso_BlitRectNoMaskComplete (void)
  1205. {
  1206.     uaecptr boardinfo = m68k_areg(regs, 0);
  1207.     uaecptr srcri = m68k_areg(regs, 1);
  1208.     uaecptr dstri = m68k_areg(regs, 2);
  1209.     uae_u16 srcx = m68k_dreg(regs, 0);
  1210.     uae_u16 srcy = m68k_dreg(regs, 1);
  1211.     uae_u16 dstx = m68k_dreg(regs, 2);
  1212.     uae_u16 dsty = m68k_dreg(regs, 3);
  1213.     uae_u16 width = m68k_dreg(regs, 4);
  1214.     uae_u16 height = m68k_dreg(regs, 5);
  1215.     uae_u8 OpCode = m68k_dreg(regs, 6);
  1216.     uae_u32 RGBFmt = m68k_dreg(regs, 7);
  1217.  
  1218.     uae_u8 Bpp = GetBytesPerPixel(RGBFmt), *srcri_ptr = NULL, *dstri_ptr = NULL;
  1219.     struct RenderInfo src_ri, dst_ri;
  1220.  
  1221.     wgfx_flushline ();
  1222.  
  1223.     if (!CopyRenderInfoStructureA2U(srcri, &src_ri) || !CopyRenderInfoStructureA2U(dstri, &dst_ri))
  1224.     return 0;
  1225.  
  1226.     /*MyOutputDebugString ("BlitRectNoMaskComplete() op 0x%2x, Bpp %d, xy(%4d,%4d) --> xy(%4d,%4d), wh(%4d,%4d)\n",
  1227.               OpCode, Bpp, srcx, srcy, dstx, dsty, width, height); */
  1228.     /*MyOutputDebugString ("-- src mem 0x%x BPR %d, dst mem 0x%x BPR %d, screen-mem 0x%x - 0x%x\n",
  1229.               src_ri.Memory, src_ri.BytesPerRow, dst_ri.Memory, dst_ri.BytesPerRow, picasso96_state.Address, picasso96_state.Extent); */
  1230.  
  1231.     switch (OpCode) {
  1232.      case 0x0C:
  1233.     BlitRect(&src_ri, &dst_ri, srcx, srcy, dstx, dsty, width, height, 0xFF);
  1234.     return 1;
  1235.  
  1236.      default:
  1237.     /* FOR NOW! */
  1238.     return 0;
  1239.     }
  1240. }
  1241.  
  1242. /* This utility function is used both by BlitTemplate() and BlitPattern() */
  1243. static __inline__ void PixelWrite1(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u32 mask)
  1244. {
  1245.     if (mask != 0xFF)
  1246.     fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
  1247.     do_put_mem_byte (mem + bits, fgpen);
  1248. }
  1249.  
  1250. static __inline__ void PixelWrite2(uae_u8 *mem, int bits, uae_u32 fgpen)
  1251. {
  1252.     do_put_mem_word (((uae_u16 *)mem) + bits, fgpen);
  1253. }
  1254.  
  1255. static __inline__ void PixelWrite3(uae_u8 *mem, int bits, uae_u32 fgpen)
  1256. {
  1257.     do_put_mem_byte (mem + bits*3, fgpen & 0x000000FF);
  1258.     *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
  1259. }
  1260.  
  1261. static __inline__ void PixelWrite4(uae_u8 *mem, int bits, uae_u32 fgpen)
  1262. {
  1263.     do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
  1264. }
  1265.  
  1266. static __inline__ void PixelWrite(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask)
  1267. {
  1268.     switch (Bpp) {
  1269.     case 1:
  1270.     if (mask != 0xFF)
  1271.         fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
  1272.     do_put_mem_byte (mem + bits, fgpen);
  1273.     break;
  1274.     case 2:
  1275.     do_put_mem_word (((uae_u16 *)mem) + bits, fgpen);
  1276.     break;
  1277.     case 3:
  1278.     do_put_mem_byte (mem + bits*3, fgpen & 0x000000FF);
  1279.     *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
  1280.     break;
  1281.     case 4:
  1282.     do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
  1283.     break;
  1284.     }
  1285. }
  1286.  
  1287. /*
  1288.  * BlitPattern:
  1289.  * 
  1290.  * Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat);
  1291.  * Inputs:
  1292.  * a0:struct BoardInfo *bi
  1293.  * a1:struct RenderInfo *ri
  1294.  * a2:struct Pattern *pattern
  1295.  * d0.w:X
  1296.  * d1.w:Y
  1297.  * d2.w:Width
  1298.  * d3.w:Height
  1299.  * d4.w:Mask
  1300.  * d7.l:RGBFormat
  1301.  * 
  1302.  * This function is used to paint a pattern on the board memory using the blitter. It is called by
  1303.  * BltPattern, if a AreaPtrn is used with positive AreaPtSz. The pattern consists of a b/w image
  1304.  * using a single plane of image data which will be expanded repeatedly to the destination RGBFormat
  1305.  * using ForeGround and BackGround pens as well as draw modes. The width of the pattern data is
  1306.  * always 16 pixels (one word) and the height is calculated as 2^Size. The data must be shifted up
  1307.  * and to the left by XOffset and YOffset pixels at the beginning.
  1308.  */
  1309. uae_u32 picasso_BlitPattern (void)
  1310. {
  1311.     uaecptr boardinfo = m68k_areg(regs, 0);
  1312.     uaecptr rinf = m68k_areg(regs, 1);
  1313.     uaecptr pinf = m68k_areg(regs, 2);
  1314.     long X = (uae_u16)m68k_dreg(regs, 0);
  1315.     long Y = (uae_u16)m68k_dreg(regs, 1);
  1316.     long W = (uae_u16)m68k_dreg(regs, 2);
  1317.     long H = (uae_u16)m68k_dreg(regs, 3);
  1318.     uae_u8 Mask = (uae_u8)m68k_dreg(regs, 4);
  1319.     uae_u32 RGBFmt = m68k_dreg(regs, 7);
  1320.  
  1321.     uae_u8 Bpp = GetBytesPerPixel(RGBFmt);
  1322.     int inversion = 0;
  1323.     struct RenderInfo ri;
  1324.     struct Pattern pattern;
  1325.     uae_u16 rows;
  1326.     uae_u32 fgpen, bgpen, value;
  1327.     uae_u8 *uae_mem, *frame_buffer_UAM;
  1328.     unsigned long ysize_mask;
  1329.  
  1330.     wgfx_flushline ();
  1331.  
  1332.     if (!CopyRenderInfoStructureA2U(rinf, &ri) || !CopyPatternStructureA2U(pinf, &pattern))
  1333.     return 0;
  1334.  
  1335.     Bpp = GetBytesPerPixel(ri.RGBFormat);
  1336.     uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset with address */
  1337.  
  1338.     if (pattern.DrawMode & INVERS)
  1339.     inversion = 1;
  1340.  
  1341.     pattern.DrawMode &= 0x03;
  1342.     if (Mask != 0xFF) {
  1343.     if (Bpp > 1)
  1344.         MyOutputDebugString ("ERROR - not obeying BlitPattern() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
  1345.     else if (pattern.DrawMode == COMP) {
  1346.         MyOutputDebugString ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitPattern(), using fallback method.\n", Mask);
  1347.         return 0;
  1348.     }
  1349.     }
  1350.  
  1351.     /*MyOutputDebugString ("BlitPattern() xy(%d,%d), wh(%d,%d) draw 0x%x, off(%d,%d), ph %d\n",
  1352.               X, Y, W, H, pattern.DrawMode, pattern.XOffset, pattern.YOffset, 1<<pattern.Size); */
  1353. #ifdef _DEBUG
  1354.     DumpPattern(&pattern);
  1355. #endif
  1356.     ysize_mask = (1 << pattern.Size) - 1;
  1357.  
  1358.     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) {
  1359.     unsigned int d = do_get_mem_word (((uae_u16 *)pattern.Memory) + (rows & ysize_mask));
  1360.     uae_u8 *uae_mem2 = uae_mem;
  1361.     long cols;
  1362.  
  1363.     if (pattern.XOffset != 0)
  1364.         d = (d << pattern.XOffset) | (d >> (16 - pattern.XOffset));
  1365.  
  1366.     for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) {
  1367.         long bits;
  1368.         long max = W - cols;
  1369.         unsigned int data = d;
  1370.  
  1371.         if (max > 16)
  1372.         max = 16;
  1373.     
  1374.         for (bits = 0; bits < max; bits++) {
  1375.         int bit_set = data & 0x8000;
  1376.         data <<= 1;
  1377.         switch (pattern.DrawMode) {
  1378.          case JAM1:
  1379.             if (inversion)
  1380.             bit_set = !bit_set;
  1381.             if (bit_set)
  1382.             PixelWrite(uae_mem2, bits, pattern.FgPen, Bpp, Mask);
  1383.             break;
  1384.          case JAM2:
  1385.             if (inversion)
  1386.             bit_set = !bit_set;
  1387.             if (bit_set)
  1388.             PixelWrite(uae_mem2, bits, pattern.FgPen, Bpp, Mask);
  1389.             else
  1390.             PixelWrite(uae_mem2, bits, pattern.BgPen, Bpp, Mask);
  1391.             break;
  1392.          case COMP:
  1393.             if (bit_set) {
  1394.             fgpen = pattern.FgPen;
  1395.  
  1396.             switch (Bpp) {
  1397.              case 1:
  1398.                 {
  1399.                 uae_u8 *addr = uae_mem2 + bits;
  1400.                 do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
  1401.                 }
  1402.                 break;
  1403.              case 2:
  1404.                 {
  1405.                 uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
  1406.                 do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
  1407.                 }
  1408.                 break;
  1409.              case 3:
  1410.                 {
  1411.                 uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
  1412.                 do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
  1413.                 }
  1414.                 break;
  1415.              case 4:
  1416.                 {
  1417.                 uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
  1418.                 do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
  1419.                 }
  1420.                 break;
  1421.             }
  1422.             }
  1423.             break;
  1424.         }
  1425.         }
  1426.     }
  1427.     }
  1428.  
  1429.     frame_buffer_UAM = ri.Memory + X*picasso96_state.BytesPerPixel + Y*ri.BytesPerRow;
  1430.     if (renderinfo_is_current_screen (&ri))
  1431.     do_blit (frame_buffer_UAM, ri.BytesPerRow, 0, 0, X, Y, W, H, 0);
  1432.  
  1433.     return 1;
  1434. }
  1435.  
  1436. /*************************************************
  1437. BlitTemplate:
  1438. **************************************************
  1439. * Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat);
  1440. * a0: struct BoardInfo *bi
  1441. * a1: struct RenderInfo *ri
  1442. * a2: struct Template *template
  1443. * d0.w: X
  1444. * d1.w: Y
  1445. * d2.w: Width
  1446. * d3.w: Height
  1447. * d4.w: Mask
  1448. * d7.l: RGBFormat
  1449. *
  1450. * This function is used to paint a template on the board memory using the blitter.
  1451. * It is called by BltPattern and BltTemplate. The template consists of a b/w image
  1452. * using a single plane of image data which will be expanded to the destination RGBFormat
  1453. * using ForeGround and BackGround pens as well as draw modes.
  1454. ***********************************************************************************/
  1455. uae_u32 picasso_BlitTemplate (void)
  1456. {
  1457.     uae_u8 inversion = 0;
  1458.     uaecptr rinf = m68k_areg(regs, 1);
  1459.     uaecptr tmpl = m68k_areg(regs, 2);
  1460.     uae_u16 X = m68k_dreg(regs, 0);
  1461.     uae_u16 Y = m68k_dreg(regs, 1);
  1462.     uae_u16 W = m68k_dreg(regs, 2);
  1463.     uae_u16 H = m68k_dreg(regs, 3);
  1464.     uae_u16 Mask = m68k_dreg(regs, 4);
  1465.     uae_u32 Fmt = m68k_dreg(regs, 7);
  1466.     struct Template tmp;
  1467.     struct RenderInfo ri;
  1468.     long rows;
  1469.     int bitoffset;
  1470.     uae_u32 fgpen, bgpen, value;
  1471.     uae_u8 *uae_mem, *uae_mem2, Bpp, *frame_buffer_UAM;
  1472.     uae_u8 *tmpl_base;
  1473.  
  1474.     wgfx_flushline ();
  1475.  
  1476.     if (!CopyRenderInfoStructureA2U(rinf, &ri) || !CopyTemplateStructureA2U(tmpl, &tmp))
  1477.     return 0;
  1478.  
  1479.     Bpp = GetBytesPerPixel(ri.RGBFormat);
  1480.     uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset into address */
  1481.  
  1482.     if (tmp.DrawMode & INVERS)
  1483.     inversion = 1;
  1484.  
  1485.     tmp.DrawMode &= 0x03;
  1486.     if (Mask != 0xFF) {
  1487.     if (Bpp > 1)
  1488.         MyOutputDebugString ("ERROR - not obeying BlitTemplate() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
  1489.     else if (tmp.DrawMode == COMP) {
  1490.         MyOutputDebugString ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitTemplate(), using fallback method.\n", Mask);
  1491.         return 0;
  1492.     }
  1493.     }
  1494.  
  1495.     /*MyOutputDebugString ("BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x \n",
  1496.               X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen); */
  1497.  
  1498.     bitoffset = tmp.XOffset % 8;
  1499.  
  1500. #ifdef _DEBUG
  1501.     DumpTemplate(&tmp, W, H);
  1502. #endif
  1503.  
  1504.     tmpl_base = tmp.Memory + tmp.XOffset/8;
  1505.  
  1506.     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) {
  1507.     long cols;
  1508.     uae_u8 *tmpl_mem = tmpl_base;
  1509.     uae_u8 *uae_mem2 = uae_mem;
  1510.     unsigned int data = *tmpl_mem;
  1511.  
  1512.     for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) {
  1513.         unsigned int byte;
  1514.         long bits;
  1515.         long max = W - cols;
  1516.  
  1517.         if (max > 8)
  1518.         max = 8;
  1519.  
  1520.         data <<= 8;
  1521.         data |= *++tmpl_mem;
  1522.  
  1523.         byte = data >> (8 - bitoffset);
  1524.  
  1525.         for (bits = 0; bits < max; bits++) {
  1526.         int bit_set = (byte & 0x80);
  1527.         byte <<= 1;
  1528.         switch (tmp.DrawMode) {
  1529.          case JAM1:
  1530.             if (inversion)
  1531.             bit_set = !bit_set;
  1532.             if (bit_set) {
  1533.             fgpen = tmp.FgPen;
  1534.             PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
  1535.             }
  1536.             break;
  1537.          case JAM2:
  1538.             if (inversion)
  1539.             bit_set = !bit_set;
  1540.             fgpen = tmp.BgPen;
  1541.             if (bit_set)
  1542.             fgpen = tmp.FgPen;
  1543.  
  1544.             PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
  1545.             break;
  1546.          case COMP:
  1547.             if (bit_set) {
  1548.             fgpen = tmp.FgPen;
  1549.  
  1550.             switch (Bpp) {
  1551.              case 1:
  1552.                 {
  1553.                 uae_u8 *addr = uae_mem2 + bits;
  1554.                 do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
  1555.                 }
  1556.                 break;
  1557.              case 2:
  1558.                 {
  1559.                 uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
  1560.                 do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
  1561.                 }
  1562.                 break;
  1563.              case 3:
  1564.                 {
  1565.                 uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
  1566.                 do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
  1567.                 }
  1568.                 break;
  1569.              case 4:
  1570.                 {
  1571.                 uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
  1572.                 do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
  1573.                 }
  1574.                 break;
  1575.             }
  1576.             }
  1577.             break;
  1578.         }
  1579.         }
  1580.     }
  1581.     }
  1582.  
  1583.     frame_buffer_UAM = ri.Memory + X*picasso96_state.BytesPerPixel + Y*ri.BytesPerRow;
  1584.     if (renderinfo_is_current_screen (&ri))
  1585.     do_blit (frame_buffer_UAM, ri.BytesPerRow, 0, 0, X, Y, W, H, 0);
  1586.  
  1587.     return 1;
  1588. }
  1589.  
  1590. /*
  1591.  * CalculateBytesPerRow:
  1592.  * a0:     struct BoardInfo
  1593.  * d0:     uae_u16 Width
  1594.  * d7:    RGBFTYPE RGBFormat
  1595.  * This function calculates the amount of bytes needed for a line of
  1596.  * "Width" pixels in the given RGBFormat.
  1597.  */
  1598. uae_u32 picasso_CalculateBytesPerRow (void)
  1599. {
  1600.     uae_u16 width = m68k_dreg(regs, 0);
  1601.     uae_u32 type = m68k_dreg(regs, 7);
  1602.  
  1603.     width = GetBytesPerPixel(type)*width;
  1604.     /*MyOutputDebugString ("CalculateBytesPerRow() = %d\n",width); */
  1605.  
  1606.     return width;
  1607. }
  1608.  
  1609. /*
  1610.  * SetDisplay:
  1611.  * a0:    struct BoardInfo
  1612.  * d0:    BOOL state
  1613.  * This function enables and disables the video display.
  1614.  * 
  1615.  * NOTE: return the opposite of the state
  1616.  */
  1617. uae_u32 picasso_SetDisplay (void)
  1618. {
  1619.     uae_u32 state = m68k_dreg(regs, 0);
  1620.     /*MyOutputDebugString ("SetDisplay(%d)\n", state);*/
  1621.     return !state;
  1622. }
  1623.  
  1624. /*
  1625.  * WaitVerticalSync:
  1626.  * a0:    struct BoardInfo
  1627.  * This function waits for the next horizontal retrace.
  1628.  */
  1629. uae_u32 picasso_WaitVerticalSync (void)
  1630. {
  1631.     /*MyOutputDebugString ("WaitVerticalSync()\n");*/
  1632.     return 1;
  1633. }
  1634.  
  1635. /* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
  1636. static void PlanarToChunky(struct RenderInfo *ri, struct BitMap *bm, long srcx, long srcy,
  1637.                long dstx, long dsty, long width, long height, uae_u8 mask)
  1638. {
  1639.     int j, bits;
  1640.  
  1641.     uae_u8 *PLANAR[8], *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat) + dsty*ri->BytesPerRow;
  1642.     int Depth = bm->Depth;
  1643.     uae_u16 rows, total_bits, value, bitoffset = srcx & 7;
  1644.     long eol_offset;
  1645.  
  1646.     /* if (mask != 0xFF) 
  1647.     MyOutputDebugString ("P2C - pixel-width = %d, bit-offset = %d\n", width, bitoffset); */
  1648.     
  1649.     /* Set up our bm->Planes[] pointers to the right horizontal offset */
  1650.     for (j = 0; j < Depth; j++) {
  1651.     uae_u8 *p = bm->Planes[j];
  1652.     if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
  1653.         p += srcx/8 + srcy*bm->BytesPerRow;
  1654.     PLANAR[j] = p;
  1655.     if ((mask & (1 << j)) == 0)
  1656.         PLANAR[j] = &all_zeros_bitmap;
  1657.     }
  1658.     eol_offset = (long)bm->BytesPerRow - ((width + 7) >> 3);
  1659.     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
  1660.     long cols;
  1661.  
  1662.     for (cols = 0; cols < width; cols += 8) {
  1663.         int k;
  1664.         uae_u32 a = 0, b = 0;
  1665.         unsigned int msk = 0xFF;
  1666.         long tmp = cols + 8 - width;
  1667.         if (tmp > 0) {
  1668.         msk <<= tmp;
  1669.         b = do_get_mem_long ((uae_u32 *)(image + cols + 4));
  1670.         if (tmp < 4)
  1671.             b &= 0xFFFFFFFF >> (32 - tmp * 8);
  1672.         else if (tmp > 4) {
  1673.             a = do_get_mem_long ((uae_u32 *)(image + cols));
  1674.             a &= 0xFFFFFFFF >> (64 - tmp * 8);
  1675.         }
  1676.         }
  1677.         for (k = 0; k < Depth; k++) {
  1678.         unsigned int data;
  1679.         if (PLANAR[k] == &all_zeros_bitmap)
  1680.             data = 0;
  1681.         else if (PLANAR[k] == &all_ones_bitmap)
  1682.             data = 0xFF;
  1683.         else {
  1684.             data = (uae_u8)(do_get_mem_word ((uae_u16 *)PLANAR[k]) >> (8 - bitoffset));
  1685.             PLANAR[k]++;
  1686.         }
  1687.         data &= msk;
  1688.         a |= p2ctab[data][0] << k;
  1689.         b |= p2ctab[data][1] << k;
  1690.         }
  1691.         do_put_mem_long ((uae_u32 *)(image + cols), a);
  1692.         do_put_mem_long ((uae_u32 *)(image + cols + 4), b);
  1693.     }
  1694.     for (j = 0; j < Depth; j++) {
  1695.         if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) {
  1696.         PLANAR[j] += eol_offset;
  1697.         }
  1698.     }
  1699.     }
  1700. }
  1701.  
  1702. /*
  1703.  * BlitPlanar2Chunky:
  1704.  * a0: struct BoardInfo *bi
  1705.  * a1: struct BitMap *bm - source containing planar information and assorted details
  1706.  * a2: struct RenderInfo *ri - dest area and its details
  1707.  * d0.w: SrcX
  1708.  * d1.w: SrcY
  1709.  * d2.w: DstX
  1710.  * d3.w: DstY
  1711.  * d4.w: SizeX
  1712.  * d5.w: SizeY
  1713.  * d6.b: MinTerm - uh oh!
  1714.  * d7.b: Mask - uh oh!
  1715.  *
  1716.  * This function is currently used to blit from planar bitmaps within system memory to chunky bitmaps
  1717.  * on the board. Watch out for plane pointers that are 0x00000000 (represents a plane with all bits "0")
  1718.  * or 0xffffffff (represents a plane with all bits "1").
  1719.  */
  1720. uae_u32 picasso_BlitPlanar2Chunky (void)
  1721. {
  1722.     uaecptr bi = m68k_areg(regs, 0);
  1723.     uaecptr bm = m68k_areg(regs, 1);
  1724.     uaecptr ri = m68k_areg(regs, 2);
  1725.     uae_u16 srcx = m68k_dreg(regs, 0) & 0xFFFF;
  1726.     uae_u16 srcy = m68k_dreg(regs, 1) & 0xFFFF;
  1727.     uae_u16 dstx = m68k_dreg(regs, 2) & 0xFFFF;
  1728.     uae_u16 dsty = m68k_dreg(regs, 3) & 0xFFFF;
  1729.     uae_u16 width = m68k_dreg(regs, 4) & 0xFFFF;
  1730.     uae_u16 height = m68k_dreg(regs, 5) & 0xFFFF;
  1731.     uae_u8 minterm = m68k_dreg(regs, 6) & 0xFF;
  1732.     uae_u8 mask = m68k_dreg(regs, 7) & 0xFF;
  1733.     int i;
  1734.     struct RenderInfo local_ri;
  1735.     uae_u8 *uaebm = NULL;
  1736.     struct BitMap local_bm;
  1737.  
  1738.     wgfx_flushline ();
  1739.  
  1740.     if (minterm != 0x0C) {
  1741.     MyOutputDebugString ("ERROR - BlitPlanar2Chunky() has minterm 0x%x, which I don't handle. Using fall-back routine.\n",
  1742.                  minterm);
  1743.     return 0;
  1744.     }
  1745.     if (!CopyRenderInfoStructureA2U(ri, &local_ri) || !CopyBitMapStructureA2U(bm, &local_bm))
  1746.     return 0;
  1747.  
  1748.     /*MyOutputDebugString ("BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
  1749.               srcx, srcy, dstx, dsty, width, height, minterm, mask, local_bm.Depth);
  1750.     MyOutputDebugString ("P2C - BitMap has %d BPR, %d rows\n", local_bm.BytesPerRow, local_bm.Rows); */
  1751.     PlanarToChunky(&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, mask);
  1752.     if (renderinfo_is_current_screen (&local_ri))
  1753.     do_blit (local_ri.Memory + dstx * GetBytesPerPixel (local_ri.RGBFormat) + dsty * local_ri.BytesPerRow,
  1754.          local_ri.BytesPerRow,
  1755.          0, 0, dstx, dsty, width, height, 0);
  1756.  
  1757.     return m68k_dreg(regs, 0);
  1758. }
  1759.  
  1760. /* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
  1761. static void PlanarToDirect(struct RenderInfo *ri, struct BitMap *bm,
  1762.                long srcx, long srcy, long dstx, long dsty,
  1763.                long width, long height, uae_u8 mask,
  1764.                struct ColorIndexMapping *cim)
  1765. {
  1766.     int j;
  1767.     int bpp = GetBytesPerPixel(ri->RGBFormat);
  1768.     uae_u8 *PLANAR[8];
  1769.     uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow;
  1770.     int Depth = bm->Depth;
  1771.     long rows;
  1772.     long eol_offset;
  1773.  
  1774.     /* Set up our bm->Planes[] pointers to the right horizontal offset */
  1775.     for (j = 0; j < Depth; j++) {
  1776.     uae_u8 *p = bm->Planes[j];
  1777.     if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
  1778.         p += srcx/8 + srcy*bm->BytesPerRow;
  1779.     PLANAR[j] = p;
  1780.     if ((mask & (1 << j)) == 0)
  1781.         PLANAR[j] = &all_zeros_bitmap;
  1782.     }
  1783.  
  1784.     eol_offset = (long)bm->BytesPerRow - ((width + (srcx & 7)) >> 3);
  1785.     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
  1786.     long cols;
  1787.     uae_u8 *image2 = image;
  1788.     unsigned int bitoffs = 7 - (srcx & 7);
  1789.     int i;
  1790.  
  1791.     for (cols = 0; cols < width; cols ++) {
  1792.         int v = 0, k;
  1793.         for (k = 0; k < Depth; k++) {
  1794.         if (PLANAR[k] == &all_ones_bitmap)
  1795.             v |= 1 << k;
  1796.         else if (PLANAR[k] != &all_zeros_bitmap) {
  1797.             v |= ((*PLANAR[k] >> bitoffs) & 1) << k;
  1798.         }
  1799.         }
  1800.  
  1801.         switch (bpp) {
  1802.          case 2:
  1803.         do_put_mem_word ((uae_u16 *)image2, cim->Colors[v]);
  1804.         image2 += 2;
  1805.         break;
  1806.          case 3:
  1807.         do_put_mem_byte (image2++, cim->Colors[v] & 0x000000FF);
  1808.         do_put_mem_word ((uae_u16 *)image2, (cim->Colors[v] & 0x00FFFF00) >> 8);
  1809.         image2 += 2;
  1810.         break;
  1811.          case 4:
  1812.         do_put_mem_long ((uae_u32 *)image2, cim->Colors[v]);
  1813.         image2 += 4;
  1814.         break;
  1815.         }
  1816.         bitoffs--;
  1817.         bitoffs &= 7;
  1818.         if (bitoffs == 7) {
  1819.         int k;
  1820.         for (k = 0; k < Depth; k++) {
  1821.             if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) {
  1822.             PLANAR[k]++;
  1823.             }
  1824.         }
  1825.         }
  1826.     }
  1827.  
  1828.     for (i = 0; i < Depth; i++) {
  1829.         if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) {
  1830.         PLANAR[i] += eol_offset;
  1831.         }
  1832.     }
  1833.     }
  1834. }
  1835.  
  1836. /*
  1837.  * BlitPlanar2Direct: 
  1838.  * 
  1839.  * Synopsis:
  1840.  * BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY, MinTerm, Mask);
  1841.  * Inputs:
  1842.  * a0:struct BoardInfo *bi
  1843.  * a1:struct BitMap *bm
  1844.  * a2:struct RenderInfo *ri
  1845.  * a3:struct ColorIndexMapping *cmi
  1846.  * d0.w:SrcX
  1847.  * d1.w:SrcY
  1848.  * d2.w:DstX
  1849.  * d3.w:DstY
  1850.  * d4.w:SizeX
  1851.  * d5.w:SizeY
  1852.  * d6.b:MinTerm
  1853.  * d7.b:Mask
  1854.  * 
  1855.  * This function is currently used to blit from planar bitmaps within system memory to direct color
  1856.  * bitmaps (15, 16, 24 or 32 bit) on the board. Watch out for plane pointers that are 0x00000000 (represents
  1857.  * a plane with all bits "0") or 0xffffffff (represents a plane with all bits "1"). The ColorIndexMapping is
  1858.  * used to map the color index of each pixel formed by the bits in the bitmap's planes to a direct color value
  1859.  * which is written to the destination RenderInfo. The color mask and all colors within the mapping are words,
  1860.  * triple bytes or longwords respectively similar to the color values used in FillRect(), BlitPattern() or
  1861.  * BlitTemplate(). 
  1862.  */
  1863. uae_u32 picasso_BlitPlanar2Direct (void)
  1864. {
  1865.     uaecptr bi = m68k_areg(regs, 0);
  1866.     uaecptr bm = m68k_areg(regs, 1);
  1867.     uaecptr ri = m68k_areg(regs, 2);
  1868.     uaecptr cim = m68k_areg(regs, 3);
  1869.     uae_u16 srcx = m68k_dreg(regs, 0);
  1870.     uae_u16 srcy = m68k_dreg(regs, 1);
  1871.     uae_u16 dstx = m68k_dreg(regs, 2);
  1872.     uae_u16 dsty = m68k_dreg(regs, 3);
  1873.     uae_u16 width = m68k_dreg(regs, 4);
  1874.     uae_u16 height = m68k_dreg(regs, 5);
  1875.     uae_u8 minterm = m68k_dreg(regs, 6);
  1876.     uae_u8 Mask = m68k_dreg(regs, 7);
  1877.     struct RenderInfo local_ri;
  1878.     uae_u8 *uaebm = NULL;
  1879.     struct BitMap local_bm;
  1880.     struct ColorIndexMapping local_cim;
  1881.  
  1882.     wgfx_flushline ();
  1883.  
  1884.     if (minterm != 0x0C) {
  1885.     MyOutputDebugString ("ERROR - BlitPlanar2Direct() has op-code 0x%x, which I don't handle. Using fall-back routine.\n",
  1886.                  minterm);
  1887.     return 0;
  1888.     }
  1889.     if (Mask != 0xFF) {
  1890.     MyOutputDebugString ("ERROR - Unsupported Mask value 0x%x in BlitPlanar2Direct(), using fallback method.\n", Mask);
  1891.     return 0;
  1892.     }
  1893.     if (!CopyRenderInfoStructureA2U (ri, &local_ri) || !CopyBitMapStructureA2U (bm, &local_bm))
  1894.     return 0;
  1895.  
  1896.     CopyColorIndexMappingA2U (cim, &local_cim);
  1897.     /* MyOutputDebugString ("BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
  1898.                 srcx, srcy, dstx, dsty, width, height, minterm, Mask, local_bm.Depth); */
  1899.     PlanarToDirect(&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, Mask, &local_cim);
  1900.     if (renderinfo_is_current_screen (&local_ri))
  1901.     do_blit (local_ri.Memory + dstx * GetBytesPerPixel (local_ri.RGBFormat) + dsty * local_ri.BytesPerRow,
  1902.          local_ri.BytesPerRow,
  1903.          0, 0, dstx, dsty, width, height, 0);
  1904.     return 1;
  1905. }
  1906.  
  1907. /* @@@ - Work to be done here!
  1908.  *
  1909.  * The address is the offset into our Picasso96 frame-buffer (pointed to by gfxmem_start)
  1910.  * where the value was put.
  1911.  *
  1912.  * Porting work: on some machines you may not need these functions, ie. if the memory for the
  1913.  * Picasso96 frame-buffer is directly viewable or directly blittable.  On Win32 with DirectX,
  1914.  * this is not the case.  So I provide some write-through functions (as per Mathias' orders!)
  1915.  */
  1916. static void write_gfx_long (uaecptr addr, uae_u32 value)
  1917. {
  1918.     uaecptr oldaddr = addr;
  1919.     int x, xbytes, y;
  1920.     uae_u8 *dst;
  1921.  
  1922.     if (!picasso_on)
  1923.     return;
  1924.  
  1925.     /*
  1926.      * Several writes to successive memory locations are a common access pattern.
  1927.      * Try to optimize it.
  1928.      */
  1929.     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
  1930.     if (addr < wgfx_min)
  1931.         wgfx_min = addr;
  1932.     if (addr + 4 > wgfx_max)
  1933.         wgfx_max = addr + 4;
  1934.     return;
  1935.     } else
  1936.     wgfx_flushline ();
  1937.  
  1938.     addr += gfxmem_start;
  1939.     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
  1940.     if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent)
  1941.     return;
  1942.  
  1943.     addr -= picasso96_state.Address;
  1944.     y = addr / picasso96_state.BytesPerRow;
  1945.  
  1946. #if 0
  1947.     DX_Invalidate (y, y);
  1948.     if (! picasso_vidinfo.extra_mem)
  1949.     return;
  1950.  
  1951.     xbytes = addr - y * picasso96_state.BytesPerRow;
  1952.     x = xbytes / picasso96_state.BytesPerPixel;
  1953.  
  1954.     if (x < picasso96_state.Width && y < picasso96_state.Height) {
  1955.     dst = lockscr();
  1956.     if (dst) {
  1957.         do_put_mem_long ((uae_u32 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
  1958.         unlockscr();
  1959.     }
  1960.     }
  1961. #else
  1962.     if (y >= picasso96_state.Height)
  1963.     return;
  1964.     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
  1965.     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
  1966.     wgfx_y = y;
  1967.     wgfx_min = oldaddr;
  1968.     wgfx_max = oldaddr + 4;
  1969. #endif
  1970. }
  1971.  
  1972. static void write_gfx_word (uaecptr addr, uae_u16 value)
  1973. {
  1974.     uaecptr oldaddr = addr;
  1975.     int x, xbytes, y;
  1976.     uae_u8 *dst;
  1977.  
  1978.     if (!picasso_on)
  1979.     return;
  1980.  
  1981.     /*
  1982.      * Several writes to successive memory locations are a common access pattern.
  1983.      * Try to optimize it.
  1984.      */
  1985.     if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) {
  1986.     if (addr < wgfx_min)
  1987.         wgfx_min = addr;
  1988.     if (addr + 2 > wgfx_max)
  1989.         wgfx_max = addr + 2;
  1990.     return;
  1991.     } else
  1992.     wgfx_flushline ();
  1993.  
  1994.     addr += gfxmem_start;
  1995.     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
  1996.     if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent)
  1997.     return;
  1998.  
  1999.     addr -= picasso96_state.Address;
  2000.     y = addr / picasso96_state.BytesPerRow;
  2001.  
  2002. #if 0
  2003.     DX_Invalidate (y, y);
  2004.     if (! picasso_vidinfo.extra_mem)
  2005.     return;
  2006.  
  2007.     xbytes = addr - y * picasso96_state.BytesPerRow;
  2008.     x = xbytes / picasso96_state.BytesPerPixel;
  2009.  
  2010.     if (x < picasso96_state.Width && y < picasso96_state.Height) {
  2011.     dst = lockscr();
  2012.     if (dst) {
  2013.         do_put_mem_word ((uae_u16 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
  2014.         unlockscr();
  2015.     }
  2016.     }
  2017. #else
  2018.     if (y >= picasso96_state.Height)
  2019.     return;
  2020.     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
  2021.     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
  2022.     wgfx_y = y;
  2023.     wgfx_min = oldaddr;
  2024.     wgfx_max = oldaddr + 2;
  2025. #endif
  2026. }
  2027.  
  2028. static void write_gfx_byte (uaecptr addr, uae_u8 value)
  2029. {
  2030.     uaecptr oldaddr = addr;
  2031.     int x, xbytes, y;
  2032.     uae_u8 *dst;
  2033.  
  2034.     if (!picasso_on)
  2035.     return;
  2036.  
  2037.     /*
  2038.      * Several writes to successive memory locations are a common access pattern.
  2039.      * Try to optimize it.
  2040.      */
  2041.     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
  2042.     if (addr < wgfx_min)
  2043.         wgfx_min = addr;
  2044.     if (addr + 1 > wgfx_max)
  2045.         wgfx_max = addr + 1;
  2046.     return;
  2047.     } else
  2048.     wgfx_flushline ();
  2049.  
  2050.     addr += gfxmem_start;
  2051.     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
  2052.     if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent)
  2053.     return;
  2054.  
  2055.     addr -= picasso96_state.Address;
  2056.     y = addr / picasso96_state.BytesPerRow;
  2057.  
  2058. #if 0
  2059.     DX_Invalidate (y, y);
  2060.     if (! picasso_vidinfo.extra_mem)
  2061.     return;
  2062.  
  2063.     xbytes = addr - y * picasso96_state.BytesPerRow;
  2064.     x = xbytes / picasso96_state.BytesPerPixel;
  2065.  
  2066.     if (x < picasso96_state.Width && y < picasso96_state.Height) {
  2067.     dst = lockscr();
  2068.     if (dst) {
  2069.         *(uae_u8 *)(dst + y * picasso_vidinfo.rowbytes + xbytes) = value;
  2070.         unlockscr();
  2071.     }
  2072.     }
  2073. #else
  2074.     if (y >= picasso96_state.Height)
  2075.     return;
  2076.     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
  2077.     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
  2078.     wgfx_y = y;
  2079.     wgfx_min = oldaddr;
  2080.     wgfx_max = oldaddr + 1;
  2081. #endif
  2082. }
  2083.  
  2084. static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr)
  2085. {
  2086.     uae_u32 *m;
  2087.     addr -= gfxmem_start & gfxmem_mask;
  2088.     addr &= gfxmem_mask;
  2089.     m = (uae_u32 *)(gfxmemory + addr);
  2090.     return do_get_mem_long(m);
  2091. }
  2092.  
  2093. static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr)
  2094. {
  2095.     uae_u16 *m;
  2096.     addr -= gfxmem_start & gfxmem_mask;
  2097.     addr &= gfxmem_mask;
  2098.     m = (uae_u16 *)(gfxmemory + addr);
  2099.     return do_get_mem_word(m);
  2100. }
  2101.  
  2102. static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr)
  2103. {
  2104.     addr -= gfxmem_start & gfxmem_mask;
  2105.     addr &= gfxmem_mask;
  2106.     return gfxmemory[addr];
  2107. }
  2108.  
  2109. static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l)
  2110. {
  2111.     uae_u32 *m;
  2112.     addr -= gfxmem_start & gfxmem_mask;
  2113.     addr &= gfxmem_mask;
  2114.     m = (uae_u32 *)(gfxmemory + addr);
  2115.     do_put_mem_long(m, l);
  2116.  
  2117.     /* write the long-word to our displayable memory */
  2118.     write_gfx_long(addr, l);
  2119. }
  2120.  
  2121. static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w)
  2122. {
  2123.     uae_u16 *m;
  2124.     addr -= gfxmem_start & gfxmem_mask;
  2125.     addr &= gfxmem_mask;
  2126.     m = (uae_u16 *)(gfxmemory + addr);
  2127.     do_put_mem_word(m, (uae_u16)w);
  2128.  
  2129.     /* write the word to our displayable memory */
  2130.     write_gfx_word(addr, (uae_u16)w);
  2131. }
  2132.  
  2133. static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b)
  2134. {
  2135.     addr -= gfxmem_start & gfxmem_mask;
  2136.     addr &= gfxmem_mask;
  2137.     gfxmemory[addr] = b;
  2138.  
  2139.     /* write the byte to our displayable memory */
  2140.     write_gfx_byte(addr, (uae_u8)b);
  2141. }
  2142.  
  2143. static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size)
  2144. {
  2145.     addr -= gfxmem_start & gfxmem_mask;
  2146.     addr &= gfxmem_mask;
  2147.     return (addr + size) < gfxmem_size;
  2148. }
  2149.  
  2150. static uae_u8 REGPARAM2 *gfxmem_xlate (uaecptr addr)
  2151. {
  2152.     addr -= gfxmem_start & gfxmem_mask;
  2153.     addr &= gfxmem_mask;
  2154.     return gfxmemory + addr;
  2155. }
  2156.  
  2157. addrbank gfxmem_bank = {
  2158.     gfxmem_lget, gfxmem_wget, gfxmem_bget,
  2159.     gfxmem_lput, gfxmem_wput, gfxmem_bput,
  2160.     gfxmem_xlate, gfxmem_check
  2161. };
  2162.  
  2163. static int resolution_compare (const void *a, const void *b)
  2164. {
  2165.     struct PicassoResolution *ma = (struct PicassoResolution *)a;
  2166.     struct PicassoResolution *mb = (struct PicassoResolution *)b;
  2167.     if (ma->res.width > mb->res.width)
  2168.     return -1;
  2169.     if (ma->res.width < mb->res.width)
  2170.     return 1;
  2171.     if (ma->res.height > mb->res.height)
  2172.     return -1;
  2173.     if (ma->res.height < mb->res.height)
  2174.     return 1;
  2175.     return ma->depth - mb->depth;
  2176. }
  2177. /* Call this function first, near the beginning of code flow
  2178.  * NOTE: Don't stuff it in InitGraphics() which seems reasonable...
  2179.  * Instead, put it in customreset() for safe-keeping.  */
  2180. void InitPicasso96 (void)
  2181. {
  2182.     static int first_time = 1;
  2183.  
  2184.     if (first_time) {
  2185.     int i;
  2186.  
  2187.     for (i = 0; i < 256; i++) {
  2188.         p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0)
  2189.                 | ((i & 64) ? 0x010000 : 0)
  2190.                 | ((i & 32) ? 0x0100 : 0)
  2191.                 | ((i & 16) ? 0x01 : 0));
  2192.         p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0)
  2193.                 | ((i & 4) ? 0x010000 : 0)
  2194.                 | ((i & 2) ? 0x0100 : 0)
  2195.                 | ((i & 1) ? 0x01 : 0));
  2196.     }
  2197. #if 0
  2198.     /* If we have some gfxmem settings, then we want Picasso96 support */
  2199.     if (gfxmem_size > 0) {
  2200.         gfxmem_mask = gfxmem_size - 1;
  2201.         gfxmemory = (uae_u8 *)xmalloc (gfxmem_size);
  2202.         map_banks(&gfxmem_bank, 0x800, gfxmem_size >> 16);
  2203.     }
  2204. #endif
  2205.     memset(&picasso96_state, 0, sizeof(struct picasso96_state_struct));
  2206.     mode_count = DX_FillResolutions (&picasso96_pixel_format);
  2207.     qsort (DisplayModes, mode_count, sizeof (struct PicassoResolution),
  2208.            resolution_compare);
  2209.  
  2210.     for (i = 0; i < mode_count; i++) {
  2211.         sprintf(DisplayModes[i].name, "%dx%d, %d-bit, %d Hz",
  2212.             DisplayModes[i].res.width, DisplayModes[i].res.height,
  2213.             DisplayModes[i].depth * 8, DisplayModes[i].refresh);
  2214.         switch (DisplayModes[i].depth) {
  2215.          case 1:
  2216.         if (DisplayModes[i].res.width > chunky.width)
  2217.             chunky.width = DisplayModes[i].res.width;
  2218.         if (DisplayModes[i].res.height > chunky.height)
  2219.             chunky.height = DisplayModes[i].res.height;
  2220.         break;
  2221.          case 2:
  2222.         if (DisplayModes[i].res.width > hicolour.width)
  2223.             hicolour.width = DisplayModes[i].res.width;
  2224.         if (DisplayModes[i].res.height > hicolour.height)
  2225.             hicolour.height = DisplayModes[i].res.height;
  2226.         break;
  2227.          case 3:
  2228.         if (DisplayModes[i].res.width > truecolour.width)
  2229.             truecolour.width = DisplayModes[i].res.width;
  2230.         if (DisplayModes[i].res.height > truecolour.height)
  2231.             truecolour.height = DisplayModes[i].res.height;
  2232.         break;
  2233.          case 4:
  2234.         if (DisplayModes[i].res.width > alphacolour.width)
  2235.             alphacolour.width = DisplayModes[i].res.width;
  2236.         if (DisplayModes[i].res.height > alphacolour.height)
  2237.             alphacolour.height = DisplayModes[i].res.height;
  2238.         break;
  2239.         }
  2240.     }
  2241.     ShowSupportedResolutions();
  2242.  
  2243.     first_time = 0;
  2244.     }
  2245.  
  2246.     if (gfxmem_size > 0) {
  2247.     memset(&picasso96_state, 0, sizeof(struct picasso96_state_struct));
  2248.     }
  2249. }
  2250.  
  2251. #endif
  2252.